import hmac
import json
import requests
import base64
import hashlib
import sys
import time

from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin2.api_client.common import (SyncQueryer)
from enum import Enum

class Side(Enum):
  BUY = "Buy"
  SELL = "Sell"

class CoinoneAuth(requests.auth.AuthBase):
  def __init__(self, key):
    self._key = AuthKey.from_file(key)

  def _gen_signature(self, payload: bytes):
    # SECRET KEY must be upper case.
    # SIGNATURE = HMAC-SHA512(payload, secret_key.upper()).TO_HEX_DIGEST()

    assert payload, "payload must be not None and not empty!"

    mac = hmac.new(self._key.secret_key_bytes, payload, hashlib.sha512)
    return mac.hexdigest()

  def __call__(self, req: requests.PreparedRequest):
    # nonce in microsecond
    nonce = str(int(time.time() * 1000 * 1000))

    body = json.loads(req.body if req.body else "{}")

    body.update({'access_token': self._key.access_key})
    body.update({'nonce': nonce})

    json_param = json.dumps(body)
    payload = base64.b64encode(json_param.encode())

    # print(json_param)

    signature = self._gen_signature(payload)

    req.headers.update({'X-COINONE-PAYLOAD': payload})
    req.headers.update({'X-COINONE-SIGNATURE': signature})
    req.prepare_headers(req.headers)

    req.prepare_body(payload, None)

    # print(req.headers)
    # print(req.body)
    # print(req.url)

    return req

class CoinonePrivateClient():
  def __init__(self, key_path: str, ip=None):
    self._auth = CoinoneAuth(key_path)
    self._url = "https://api.coinone.co.kr"

    self._query = SyncQueryer(api_host=self._url, auth=self._auth, ip=ip)

  def get_open_order(self, currency: str):
    assert currency, "currency must be not None and not empty!"

    method = "POST"
    json = {
      "currency": currency,
    }
    path = "/v2/order/limit_orders/"

    response = self._query.query(method=method, path=path, json=json)
    return response.json()

  def cancel_order(self, order_id: str, qty: str, currency: str):
    assert order_id, "order_id must be not None and not empty!"
    assert qty, "qty must be not None and not empty!"
    assert currency, "currency must be not None and not empty!"

    method = "POST"
    json = {
      'order_id': order_id,
      'qty': qty,
      'currency': currency,
    }
    path = "/v2/order/cancel/"

    response = self._query.query(method=method, path=path, json=json)
    return response.json()

  def submit_order(
    self,
    currency: str,
    side: Side,
    qty: str,
    price: str,
    is_post_only: bool = None,
  ):
    assert currency, "currency must be not None and not empty!"
    assert side, "side must be not None!"
    assert qty, "qty must be not None and not empty!"
    assert price, "price must be not None and not empty!"

    method = "POST"
    json = {
      'currency': currency,
      'qty': qty,
      'price': price,
      'is_post_only': is_post_only,
    }
    path = None
    if side == Side.BUY:
      path = "/v2/order/limit_buy/"
    elif side == Side.SELL:
      path = "/v2/order/limit_sell/"
    else:
      assert False, "side must be one of buy and sell!"

    response = self._query.query(method=method, path=path, json=json)
    return response.json()

# api doc url
# https://doc.coinone.co.kr/

if __name__ == "__main__":
  key_path = sys.argv[1]
  
  coinone = CoinonePrivateClient(key_path)
  info = coinone.get_open_order("BTC")
  # info = coinone.cancel_order('bafd3a24-6a17-49f0-a687-f542bd880e40', '0.12', 'BTC')
  # info = coinone.submit_order("BTC", Side.SELL, "0.00000001", "10000000")
  print(json.dumps(info, indent=2))
